The All Mighty Object

The All Mighty Object

Euphoria as a One Data-type Language


Here's a interesting way to write programs: how would you like to write entire programs using just a single data-type (hint: Euphoria lets you do this), and understanding how this is possible will help you program with the other built-in data-types: atoms, integers, and sequences.

Some background first. A computer is a just a machine that, when it comes down to it, works only with numbers; Euphoria is a language that lets you direct how the computer is to work with those numbers. So when you think about it, only one data-type is really needed. In Euphoria that is called an object (some other languages call these variants). Any Euphoria object contains either a single number or a collection of zero or more other objects -- that's it -- really! The object data-type does it all.

A variable is a name given to the value of an object. To use a variable you must introduce it (also called 'declaring it'). There are some restrictions on what you can give as a name for variables, but generally it must start with a letter, and then have zero or more other letters, digits or underscore ('_') characters. Also, you can't have a name that clashes with another variable declared elsewhere in the program, but see Scoping Rules for more details about that.

  • declare using object and an identifier
object x 
  • assign a value to the variable
x = 5 

Hint: When giving an variable an initial value while declaring it, you can save on typing by...

-- introducing on one line 
object x = 5 
 
-- and/or introducing several variables at once 
object x = 3, y = 2 

Hint: The double dash, - - , is the Euphoria comment marker; anything following a double dash to the end of the line is ignored by Euphoria.

The value you give an object is anything you can imagine and is written in a style most convenient for you.

object z 
 
-- any individual value in choice of format  
-- these are Euphoria "atom" examples 
 
z = 4           -- an integer 
z = -5          -- a negative integer 
z = 3.14159     -- a real number 
z = 1_000_000   -- a million using underscores for spacing 
z = 1e6         -- a million in scientific notation   
z = 'a'         -- the character 'a' 
 
-- any collection of values in choice of format 
-- these are Euphoria "sequence" examples 
-- use { } for grouping items in an object 
 
z = {}                          -- empty 
z = { 1, 2, 3, 4, 5}            -- a flat list of numbers 
z = { {1,2}, {3,4}, {5,6} }     -- a 2x3 matrix of numbers 
z = "Hello Euphoria!"           -- a character string 
z = { "one", "two", "three"}    -- put strings inside a sequence 
z = { {1,"one"}, {2,"two"}, {3,"three"} } -- mix values together 
z =  
` 
Write anything 
you want. 
`                           -- free-form raw text 

You can do anything with an object in your program. An object variable may be huge (only limited by computer memory) on one line and reduced to an integer on the next line. The Euphoria object is very dynamic: create, delete, extend, alter, reshape, change items, remove items, search, sort, ..., lots and lots of possibilities.

It is possible to write a program of any size using just the single object data-type.

Aside: Mathematical numbers are infinite in size (small or large) and in limitless in accuracy. Objects use computer numbers which are limited in size and accuracy. Calculations with computer numbers can be slightly off or even strangely wrong in special cases. Euphoria follows the same IEEE standards as all modern languages; you have to understand how to use computer numbers regardless of your choice of language. Values in an object are either computer integer or computer float numbers.

Displaying Objects

Euphoria converts all values into numbers that a computer can process; only numbers remain. At any time you can use print to display the numbers contained in an object:

Hint: The question mark, ? , is a Euphoria shortcut for print :

    -- both ? and print have the same output 
? { 3, 3.333 } 
    --> { 3, 3.33 } 
print(1, { 3, 3.333 } ) 
    --> { 3, 3.333 } 

Using print to output a variety of objects:

-- everything is a number 
 
print(1, {1,2,3,4} ) 
    --> {1,2,3,4} 
print(1, 1_000_000 ) 
    --> 1000000 
print(1, 'a') 
    --> 97 
print(1, "Hello Euphoria") 
    -->     {72,101,108,108,111,32,69,117,112,104,111,114,105,97} 

Notice that all of the features that make data entry convenient vanish: spacers in numbers are removed and individual characters become integers. What remains is either a single number or a collection of numbers.

But, all is not lost! If you use puts you can display characters and character strings:

-- characters and character strings output as expected 
 
puts(1, 'a') 
    --> a 
puts(1, 97 ) 
    --> a 
puts(1, "Hello Euphoria") 
    --> Hello Euphoria 
puts(1, {72,101,108,108,111,32,69,117,112,104,111,114,105,97} ) 
    --> Hello Euphoria 

The traditional ASCII standard defines a number:glyph relationship for what we call plain text characters, digits, and punctuation. The current UTF8 standard retains these relationships. (A glyph is "what you see when something gets printed.")

If a number has a "sensible value" then the puts procedure ( short for put string) will display glyphs instead of a numbers. Numbers that do not have a corresponding glyph will display as noise.

Note: A string is a "sequence of characters." A string object is therefore a flat list of items; we say that a string has a simple one-dimensional shape. You can put strings as items inside a larger object; the object is now multi-dimensional; this object contains text data but is no longer a character string. The puts procedure will only display a character string:

-- puts will display a character string  
object str = "A string is flat." 
 
-- puts will NOT display arbitrary text 
object txt = { "An object ", "can contain text ",  
               "but that object is ", "no longer a string." } 

The output for puts:

puts(1, str) 
    --> A string is flat. 
     
puts(1, txt) 
    --> error 
    -- sequence found inside character string  

Hint: Using puts to display a complex object (even if it contains text) is common mistake.

Again, all is not lost! The display procedure is used to output complicated objects:

include std/console.e 
 
display( txt ) 
    -- { 
    -- "An object ", 
    -- "can contain text ", 
    -- "but that object is ", 
    -- "no longer a string." 
    -- } 

The display procedure examines the items inside an object, makes an "educated guess", and displays the object in the most readable form it can. Note: Before using display you have to write include std/console.e because this procedure is read from a library file.

Use pretty_print, another library procedure, to display an object in various ways:

include std/pretty.e 
 
pretty_print(1, txt, {1} ) 
    -- { 
    --    {65'A',110'n',32' ',111'o',98'b',106'j',101'e',99'c',116't',32' '}, 
    --  {99'c',97'a',110'n',32' ',99'c',111'o',110'n',116't',97'a',105'i',110'n', 
    --  32' ',116't',101'e',120'x',116't',32' '}, 
    --  {98'b',117'u',116't',32' ',116't',104'h',97'a',116't',32' ',111'o',98'b', 
    --  106'j',101'e',99'c',116't',32' ',105'i',115's',32' '}, 
    --  {110'n',111'o',32' ',108'l',111'o',110'n',103'g',101'e',114'r',32' ',97'a', 
    --  32' ',115's',116't',114'r',105'i',110'n',103'g',46'.'} 
    -- }    
 
pretty_print(1, txt, {2} ) 
    -- { 
    -- "An object ", 
    -- "can contain text ", 
    -- "but that object is ", 
    -- "no longer a string." 
    -- } 

When doing something fancy, it is assumed that you know what you want. You can specify output exactly with the printf procedure:

printf(1, "%s%s%s%s", txt) 
    --> An object can contain text but that object is no longer a string. 

The second argument, "%s%s%s%s", is a format string that determines the appearance of txt when it is output. The codes printf uses are similar to those found in most languages.

Object Programming

There is lots of power and flexibilty in the object data-type. If you are only interested in text data then you can input and output character strings just as easily as with a conventional language. If you are only interested in numbers then an object can be any number or collection of numbers. Any data arrangement you can imagine can be represented by an object.

The computer science defines an object as "a location in memory having a value that is referenced by an identifier." This definition of an object has long been used by compiler designers; to a language designer an "object" is a real and tangible thing that makes computers work. In Euphoria, an identifier is used to access just data that belongs to an object. This is the simple and fast way to use objects.

An "object" in an "object oriented programming" (OOP) language is much more complicated. In an OOP language an object identifier is associated with both data and routines. OOP style languages are larger, more complicated, harder to learn, harder to program, and slower than Euphoria. Simple, fast, and friendly can not be used to describe languages like Python, Java, or Ruby. The art of programming is knowing when to use a truck (like an OOP language) or when to use a sports car (like Euphoria.)

Object, Atom, Integer, Sequence, User-Defined

Using only the object data-type is possible, but practical Euphoria programs are designed around atom and sequence data-types. It is best to view an object and an integer as helper data-types; they are used for special purposes.

The object is the root data-type that makes Euphoria operate. Using an object for everything is overkill; we use object data-types sparingly and even call it one of the "helper" data-types. The atom and sequence are the two branches used for most programming. The integer is a branch of the atom type; it is also used as a "helper" data-type. When inventing a user-defined data-type you can use all four built-in data-types and other user-defined types to create the perfect custom type for your program.

When you narrow down the values a variable can represent then programs become: easier to read and write, faster, and less likely to have bugs.

  • If a variable is to be used with only individual numbers then the atom is the best choice.
  • If your data is always going be be a collection of values then the sequence data-type is the best choice.
  • The integer is a subset of the atom data-type; use an integer for counting and indexing.
  • The object data-type has special uses when you can not know in advance if a variable will be used for atom values or sequence values. For example a variable that reads a file normally gets a character string and is thus a sequence, but when the file is empty or end-of-file an atom is returned--the object data-type is the only way to read either a sequence or an atom.
  • It is possible to define a user-defined data-type to exactly specify what values are permitted for a variable. These data-types are useful when developing a program since they catch errors.

Real programs are written with atom and sequence data-types and use object and integer as "helper" data-types. Larger programs can use user-defined data-types to advantage.

Search



Quick Links

User menu

Not signed in.

Misc Menu